<template>
  <div class="page-wrap">
    <el-card shadow="never" class="mb-12">
      <div class="toolbar">
        <el-date-picker v-model="filters.range" type="daterange" start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" />
        <el-select v-model="filters.granularity" class="w-140">
          <el-option label="按日" value="day" />
          <el-option label="按周" value="week" />
          <el-option label="按月" value="month" />
        </el-select>
        <el-select v-model="rowsSelected" multiple collapse-tags class="w-260" placeholder="行维度">
          <el-option v-for="d in dimensions" :key="d.value" :label="d.label" :value="d.value" />
        </el-select>
        <el-select v-model="colsSelected" multiple collapse-tags class="w-260" placeholder="列维度">
          <el-option v-for="d in dimensions" :key="d.value" :label="d.label" :value="d.value" />
        </el-select>
        <el-select v-model="valsSelected" multiple collapse-tags class="w-220" placeholder="指标">
          <el-option v-for="m in metrics" :key="m.value" :label="m.label" :value="m.value" />
        </el-select>
        <el-button type="primary" @click="renderPivot">分析</el-button>
        <el-button @click="filterVisible=true">筛选</el-button>
        <el-button @click="exportCsv">导出</el-button>
        <span class="spacer"></span>
        <el-select v-model="chartType" class="w-140" placeholder="图表">
          <el-option label="柱状图" value="bar" />
          <el-option label="折线图" value="line" />
        </el-select>
        <el-button @click="refreshChart">绘图</el-button>
        <el-divider direction="vertical" />
        <el-input v-model="schemeName" placeholder="方案名" class="w-180" />
        <el-button @click="saveScheme">保存方案</el-button>
        <el-select v-model="schemeSelected" placeholder="加载方案" class="w-180" @change="loadScheme">
          <el-option v-for="s in schemes" :key="s.name" :label="s.name" :value="s.name" />
        </el-select>
        <el-button type="danger" @click="removeScheme" :disabled="!schemeSelected">删除方案</el-button>
      </div>
    </el-card>
    <!-- 拖拽字段面板：支持拖入/拖出与顺序调整 -->
    <el-card shadow="never" class="mb-12">
      <div class="panel">
        <div class="pool">
          <div class="title">字段池</div>
          <div class="chips">
            <span
              v-for="d in dimensions"
              :key="'dim-'+d.value"
              class="chip dim"
              draggable="true"
              @dragstart="onPoolDragStart('dim', d.value)"
            >{{ d.label }}</span>
            <span
              v-for="m in metrics"
              :key="'met-'+m.value"
              class="chip met"
              draggable="true"
              @dragstart="onPoolDragStart('met', m.value)"
            >{{ m.label }}</span>
          </div>
        </div>
        <div class="zones">
          <div class="zone" @dragover.prevent @drop="onZoneDrop('rows')">
            <div class="zone-title">行维度</div>
            <div class="chips">
              <span
                v-for="(f,idx) in rowsSelected"
                :key="'rows-'+f"
                class="chip dim"
                draggable="true"
                @dragstart="onChipDragStart('rows', idx, f)"
                @dragover.prevent
                @drop="onChipDrop('rows', idx)"
              >{{ labelOf(f) }}<i class="rm" @click.stop="removeField('rows', f)">×</i></span>
            </div>
          </div>
          <div class="zone" @dragover.prevent @drop="onZoneDrop('cols')">
            <div class="zone-title">列维度</div>
            <div class="chips">
              <span
                v-for="(f,idx) in colsSelected"
                :key="'cols-'+f"
                class="chip dim"
                draggable="true"
                @dragstart="onChipDragStart('cols', idx, f)"
                @dragover.prevent
                @drop="onChipDrop('cols', idx)"
              >{{ labelOf(f) }}<i class="rm" @click.stop="removeField('cols', f)">×</i></span>
            </div>
          </div>
          <div class="zone" @dragover.prevent @drop="onZoneDrop('vals')">
            <div class="zone-title">指标</div>
            <div class="chips">
              <span
                v-for="(f,idx) in valsSelected"
                :key="'vals-'+f"
                class="chip met"
                draggable="true"
                @dragstart="onChipDragStart('vals', idx, f)"
                @dragover.prevent
                @drop="onChipDrop('vals', idx)"
              >{{ labelMetric(f) }}<i class="rm" @click.stop="removeField('vals', f)">×</i></span>
            </div>
          </div>
        </div>
      </div>
    </el-card>

    <div ref="s2Container" class="s2-container"></div>
    <div ref="chartRef" class="chart-container"></div>

    <!-- 筛选面板 -->
    <el-drawer v-model="filterVisible" title="筛选" size="40%">
      <div class="filters-grid">
        <el-form label-width="90px">
          <el-form-item label="品牌">
            <el-select v-model="filterState.brands" multiple filterable collapse-tags class="w-full" :options="brandOptions" />
          </el-form-item>
          <el-form-item label="品类">
            <el-select v-model="filterState.categories" multiple filterable collapse-tags class="w-full" :options="categoryOptions" />
          </el-form-item>
          <el-form-item label="款号">
            <el-select v-model="filterState.styleNos" multiple filterable collapse-tags class="w-full" :options="styleNoOptions" />
          </el-form-item>
          <el-form-item label="颜色">
            <el-select v-model="filterState.colors" multiple filterable collapse-tags class="w-full" :options="colorOptions" />
          </el-form-item>
          <el-form-item label="尺码">
            <el-select v-model="filterState.sizes" multiple filterable collapse-tags class="w-full" :options="sizeOptions" />
          </el-form-item>
          <el-form-item label="门店/仓">
            <el-select v-model="filterState.warehouses" multiple filterable collapse-tags class="w-full" :options="warehouseOptions" />
          </el-form-item>
          <el-form-item label="TopN">
            <div class="topn">
              <el-input-number v-model="topN.count" :min="0" :max="200" />
              <el-select v-model="topN.metric" class="w-160">
                <el-option label="销量(件)" value="qty" />
                <el-option label="销售额(估)" value="amount" />
              </el-select>
              <el-select v-model="topN.dimension" class="w-160" placeholder="按维度">
                <el-option v-for="d in allSelectedDims" :key="d" :label="labelOf(d)" :value="d" />
              </el-select>
            </div>
          </el-form-item>
          <el-form-item label="排序">
            <div class="sort">
              <el-select v-model="sortBy.field" class="w-160" placeholder="维度">
                <el-option v-for="d in allSelectedDims" :key="d" :label="labelOf(d)" :value="d" />
              </el-select>
              <el-select v-model="sortBy.metric" class="w-160" placeholder="指标">
                <el-option label="销量(件)" value="qty" />
                <el-option label="销售额(估)" value="amount" />
              </el-select>
              <el-select v-model="sortBy.method" class="w-140">
                <el-option label="降序" value="DESC" />
                <el-option label="升序" value="ASC" />
              </el-select>
            </div>
          </el-form-item>
        </el-form>
        <div class="text-right">
          <el-button @click="resetFilters">重置</el-button>
          <el-button type="primary" @click="applyFilters">应用</el-button>
        </div>
      </div>
    </el-drawer>
  </div>
  </template>

<script setup>
import { ref, reactive, computed, onMounted, watch, nextTick } from 'vue'
import { useStockStore } from '@/stores/stock.js'
import { useProductStore } from '@/stores/product.js'
import { useOrderStore } from '@/stores/order.js'
import { PivotSheet } from '@antv/s2'
import '@antv/s2/dist/style.min.css'
import * as echarts from 'echarts'

const stock = useStockStore()
const product = useProductStore()
const order = useOrderStore()

const dimensions = [
  { label: '日期', value: 'date' },
  { label: '门店/仓库', value: 'warehouse' },
  { label: '款号', value: 'styleNo' },
  { label: '颜色', value: 'color' },
  { label: '尺码', value: 'size' },
  { label: '品牌', value: 'brand' },
  { label: '品类', value: 'category' },
  { label: '渠道', value: 'channel' },
  { label: '收银员', value: 'operator' },
]
const metrics = [
  { label: '销量(件)', value: 'qty' },
  { label: '销售额(估)', value: 'amount' },
  { label: '客单价(估)', value: 'avgAmount' },
]

const filters = reactive({ range: [], granularity: 'day' })
const rowsSelected = ref(['date'])
const colsSelected = ref(['styleNo'])
const valsSelected = ref(['qty', 'amount'])
const s2Container = ref(null)
const chartRef = ref(null)
let s2 = null
let chart = null

onMounted(()=>{
  if(!stock.stockList.length) stock.initializeStock()
  if(!product.productList.length) product.initializeProducts()
  order.initialize()
  renderPivot()
})
watch([rowsSelected, colsSelected, valsSelected, () => filters.granularity, () => filters.range], () => { renderPivot() }, { deep: true })

function inRange(dateIso){
  if (!filters.range || filters.range.length !== 2) return true
  const [start, end] = filters.range
  const d = new Date(dateIso).toISOString().slice(0,10)
  return (!start || d >= start) && (!end || d <= end)
}

function keyOf(item, dim){
  if (dim === 'date') return formatByGranularity(item.date || item.createdAt || '')
  if (dim === 'warehouse') return item.warehouse || item.store || '—'
  if (dim === 'styleNo') return item.styleNo || item.code || '—'
  if (dim === 'color') return item.color || '—'
  if (dim === 'size') return item.size || '—'
  if (dim === 'brand') return item.brand || '—'
  if (dim === 'category') return item.category || '—'
  if (dim === 'channel') return item.channel || '—'
  if (dim === 'operator') return item.operator || '—'
  return '—'
}

// 标签辅助
function labelOf(v) {
  const d = dimensions.find(d => d.value === v)
  return d ? d.label : v
}
function labelMetric(v) {
  const m = metrics.find(m => m.value === v)
  return m ? m.label : v
}

function formatByGranularity(iso){
  const d = new Date(iso)
  if (filters.granularity === 'month') return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}`
  if (filters.granularity === 'week') {
    const onejan = new Date(d.getFullYear(),0,1)
    const diff = Math.floor(((d - onejan) / 86400000 + onejan.getDay()+1) / 7)
    return `${d.getFullYear()}-W${String(diff).padStart(2,'0')}`
  }
  return `${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`
}

function buildRecords(){
  // 基础数据：以库存历史 outbound 为主，辅以前端商品档案字段
  const pidToProduct = Object.fromEntries(product.productList.map(p => [p.id, p]))
  const outbound = stock.getStockHistory(null, 'outbound').filter(r => inRange(r.date))
  const records = outbound.map(r => {
    const p = pidToProduct[r.productId]
    return {
      date: r.date,
      qty: Number(r.quantity || 0),
      amount: Number(r.quantity || 0) * Number(p?.salePrice || 0),
      styleNo: p?.styleNo, color: p?.color, size: p?.size,
      brand: p?.brand, category: p?.category,
      operator: r.operator, warehouse: r.warehouse,
      channel: '线下',
    }
  })
  // 应用筛选
  return records.filter(r => {
    if (filterState.brands.length && !filterState.brands.includes(r.brand)) return false
    if (filterState.categories.length && !filterState.categories.includes(r.category)) return false
    if (filterState.styleNos.length && !filterState.styleNos.includes(r.styleNo)) return false
    if (filterState.colors.length && !filterState.colors.includes(r.color)) return false
    if (filterState.sizes.length && !filterState.sizes.includes(r.size)) return false
    if (filterState.warehouses.length && !filterState.warehouses.includes(r.warehouse)) return false
    return true
  })
}

function renderPivot(){
  const data = buildRecords().map(rec => {
    const row = { ...rec }
    // 将维度预格式化
    rowsSelected.value.forEach(d => { row[d] = keyOf(rec, d) })
    colsSelected.value.forEach(d => { row[d] = keyOf(rec, d) })
    row.qty = Number(row.qty || 0)
    row.amount = Number(row.amount || 0).toFixed(2)
    return row
  })
  const dataCfg = {
    fields: {
      rows: rowsSelected.value,
      columns: colsSelected.value,
      values: valsSelected.value,
      valueInCols: true,
    },
    meta: [
      ...dimensions.map(d => ({ field: d.value, name: d.label })),
      ...metrics.map(m => ({ field: m.value, name: m.label }))
    ],
    data,
  }
  const config = {
    width: s2Container.value.clientWidth,
    height: 560,
    hierarchyType: 'grid',
    style: { layoutWidthType: 'colAdaptive' },
    totals: { row: { showGrandTotals: true, showSubTotals: true }, col: { showGrandTotals: true, showSubTotals: true } },
    conditions: {
      text: [],
      background: [
        {
          field: 'qty', mapping: value => ({ fill: Number(value) > 0 ? '#e6fffb' : '#fff' })
        },
        {
          field: 'amount', mapping: value => ({ fill: Number(value) > 0 ? '#fff7e6' : '#fff' })
        }
      ]
    },
    sort: {
      sortFunc: (params) => {
        // 简化排序：依据配置的 sortBy，优先对指定维度/指标进行排序
        if (!sortBy.field || !sortBy.metric) return 0
        const f = sortBy.field
        const m = sortBy.metric
        const a = params.data?.[f]?.value || params.data?.[m]?.value
        const b = params.prevData?.[f]?.value || params.prevData?.[m]?.value
        const diff = Number(a) - Number(b)
        return sortBy.method === 'DESC' ? -diff : diff
      }
    }
  }
  if (s2) { s2.setDataCfg(dataCfg); s2.setOptions(config); s2.render(); return }
  s2 = new PivotSheet(s2Container.value, dataCfg, config)
  s2.render()
}

function exportCsv(){
  if (!s2) return
  const table = s2.facet.getCanvasElement()?.toDataURL ? null : null
  // 退化为导出当前聚合数据
  const results = s2.dataSet.getMultiData({})
  const headers = ['维度/指标', ...results[0]?.values?.map(v=>v.field) || []]
  const lines = results.map(r => [r.formattedValue, ...(r.values||[]).map(v=>v.formattedValue)])
  const csv = [headers.join(','), ...lines.map(l => l.join(','))].join('\n')
  const blob = new Blob(['\ufeff' + csv], { type: 'text/csv;charset=utf-8;' })
  const a = document.createElement('a')
  a.href = URL.createObjectURL(blob)
  a.download = `零售分析_${new Date().toISOString().slice(0,10)}.csv`
  a.click()
}

// 过滤器
const filterVisible = ref(false)
const filterState = reactive({ brands: [], categories: [], styleNos: [], colors: [], sizes: [], warehouses: [] })
const brandOptions = computed(()=> Array.from(new Set(product.productList.map(p=>p.brand))).filter(Boolean))
const categoryOptions = computed(()=> Array.from(new Set(product.productList.map(p=>p.category))).filter(Boolean))
const styleNoOptions = computed(()=> Array.from(new Set(product.productList.map(p=>p.styleNo))).filter(Boolean))
const colorOptions = computed(()=> Array.from(new Set(product.productList.map(p=>p.color))).filter(Boolean))
const sizeOptions = computed(()=> Array.from(new Set(product.productList.map(p=>p.size))).filter(Boolean))
const warehouseOptions = computed(()=> Array.from(new Set(stock.stockList.map(p=>p.warehouse))).filter(Boolean))
function resetFilters(){ Object.assign(filterState, { brands: [], categories: [], styleNos: [], colors: [], sizes: [], warehouses: [] }) }
function applyFilters(){ filterVisible.value = false; renderPivot() }

// TopN/排序
const allSelectedDims = computed(()=> Array.from(new Set([...rowsSelected.value, ...colsSelected.value])))
const topN = reactive({ count: 0, metric: 'qty', dimension: '' })
const sortBy = reactive({ field: '', metric: 'qty', method: 'DESC' })

// 方案保存/加载
const SCHEME_KEY = 'erppos_retail_analytics_schemes'
const schemes = ref(JSON.parse(localStorage.getItem(SCHEME_KEY) || '[]'))
const schemeName = ref('')
const schemeSelected = ref('')
function saveScheme(){
  const scheme = { name: schemeName.value || `方案${Date.now()}`, rows: rowsSelected.value, cols: colsSelected.value, vals: valsSelected.value, granularity: filters.granularity, filters: JSON.parse(JSON.stringify(filterState)) }
  const list = schemes.value.filter(s=>s.name!==scheme.name)
  list.unshift(scheme)
  schemes.value = list
  localStorage.setItem(SCHEME_KEY, JSON.stringify(list))
  schemeSelected.value = scheme.name
}
function loadScheme(name){
  const s = schemes.value.find(x=>x.name===name)
  if (!s) return
  rowsSelected.value = [...s.rows]
  colsSelected.value = [...s.cols]
  valsSelected.value = [...s.vals]
  filters.granularity = s.granularity
  Object.assign(filterState, s.filters || {})
  nextTick(()=> renderPivot())
}
function removeScheme(){
  if (!schemeSelected.value) return
  schemes.value = schemes.value.filter(s=>s.name!==schemeSelected.value)
  localStorage.setItem(SCHEME_KEY, JSON.stringify(schemes.value))
  schemeSelected.value = ''
}

// 图表联动
const chartType = ref('bar')
function refreshChart(){
  if (!s2) return
  const results = s2.dataSet.getMultiData({})
  const x = results.map(r => r.formattedValue)
  const valueFields = (results[0]?.values || []).map(v=>v.field)
  const series = valueFields.map((f,i) => ({ name: f, type: chartType.value, data: results.map(r => Number((r.values[i]?.data || 0))) }))
  if (!chart) chart = echarts.init(chartRef.value)
  chart.setOption({ tooltip: { trigger: 'axis' }, legend: {}, xAxis: { type: 'category', data: x }, yAxis: { type: 'value' }, series })
}

// 拖拽与顺序调整
const dragging = reactive({ fromArea: '', fromIndex: -1, field: '', type: '' })
function onPoolDragStart(type, field){ dragging.type = type; dragging.field = field; dragging.fromArea='pool'; dragging.fromIndex=-1 }
function onZoneDrop(area){
  const f = dragging.field
  if (!f) return
  if (area === 'rows' || area === 'cols') {
    if (!dimensions.some(d => d.value === f)) return
    if (area === 'rows') {
      colsSelected.value = colsSelected.value.filter(x => x !== f)
      if (!rowsSelected.value.includes(f)) rowsSelected.value = [...rowsSelected.value, f]
    } else {
      rowsSelected.value = rowsSelected.value.filter(x => x !== f)
      if (!colsSelected.value.includes(f)) colsSelected.value = [...colsSelected.value, f]
    }
  } else if (area === 'vals') {
    if (!metrics.some(m => m.value === f)) return
    if (!valsSelected.value.includes(f)) valsSelected.value = [...valsSelected.value, f]
  }
  dragging.fromArea=''; dragging.fromIndex=-1; dragging.field=''; dragging.type=''
}
function onChipDragStart(area, idx, f){ dragging.fromArea = area; dragging.fromIndex = idx; dragging.field = f; dragging.type = dimensions.some(d=>d.value===f)?'dim':'met' }
function onChipDrop(area, idx){
  const f = dragging.field
  if (!f) return
  const getList = (a)=> a==='rows'?rowsSelected.value: a==='cols'?colsSelected.value: valsSelected.value
  const setList = (a, list)=> { if(a==='rows') rowsSelected.value=[...list]; else if(a==='cols') colsSelected.value=[...list]; else valsSelected.value=[...list] }
  // 从来源移除
  if (dragging.fromArea && dragging.fromArea !== 'pool') {
    const fromList = getList(dragging.fromArea)
    const fromIdx = fromList.indexOf(f)
    if (fromIdx > -1) fromList.splice(fromIdx, 1)
    setList(dragging.fromArea, fromList)
  }
  // 插入到目标位置
  const target = getList(area)
  // 若目标已有该字段，先移除再插入到新位置
  const existIdx = target.indexOf(f)
  if (existIdx > -1) target.splice(existIdx, 1)
  target.splice(Math.max(0, Math.min(idx, target.length)), 0, f)
  setList(area, target)
  dragging.fromArea=''; dragging.fromIndex=-1; dragging.field=''; dragging.type=''
}
function removeField(area, f){
  if (area === 'rows') rowsSelected.value = rowsSelected.value.filter(x => x !== f)
  if (area === 'cols') colsSelected.value = colsSelected.value.filter(x => x !== f)
  if (area === 'vals') valsSelected.value = valsSelected.value.filter(x => x !== f)
}
</script>

<style scoped>
.page-wrap { padding: 16px; }
.toolbar { display: flex; gap: 12px; align-items: center; margin-bottom: 12px; }
.w-160 { width: 160px; }
.w-180 { width: 180px; }
.w-140 { width: 140px; }
.w-220 { width: 220px; }
.w-260 { width: 260px; }
.mb-12 { margin-bottom: 12px; }
.s2-container { width: 100%; height: 560px; }
.chart-container { width: 100%; height: 360px; margin-top: 12px; background: #fff; border-radius: 8px; }
.spacer { flex: 1; }
.filters-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
.w-full { width: 100%; }
.topn, .sort { display: flex; gap: 12px; align-items: center; }
.panel { display: grid; grid-template-columns: 280px 1fr; gap: 12px; }
.pool { border-right: 1px solid #eee; padding-right: 12px; }
.pool .title { font-weight: 600; margin-bottom: 8px; }
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip { padding: 2px 8px; border-radius: 12px; background: #f3f4f6; cursor: move; user-select: none; }
.chip.dim { background: #e5f3ff; }
.chip.met { background: #e8f7ee; }
.chip .rm { margin-left: 6px; cursor: pointer; }
.zones { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 12px; }
.zone { border: 1px dashed #cbd5e1; border-radius: 8px; padding: 8px; min-height: 60px; }
.zone-title { font-size: 12px; color: #64748b; margin-bottom: 6px; }
</style>


